package net.siufung.core.utils;

import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.CollectionLikeType;
import com.fasterxml.jackson.databind.type.MapType;
import com.google.common.base.Strings;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.TimeZone;

/**
 * JacksonUtil 工具类
 * @author 陈建峰
 * @since 2022/4/26 5:28 下午
 */
public class JacksonUtil {

    /**
     * 获取 ObjectMapper 实例
     * @return ObjectMapper
     */
    public static ObjectMapper getInstance() {
        return JacksonHolder.INSTANCE;
    }

    private static class JacksonHolder {
        private static final ObjectMapper INSTANCE = new JacksonObjectMapper();
    }

    private static class JacksonObjectMapper extends ObjectMapper {

        private static final long serialVersionUID = 4288193147502386170L;

        JacksonObjectMapper() {
            super(JsonFactory.builder()
                    .configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true)
                    .configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS, true)
                    .build());
            super.setLocale(Locale.CHINA);
            super.setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN, Locale.CHINA));
            super.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
            super.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            super.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
            super.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
            super.findAndRegisterModules();
        }

        JacksonObjectMapper(ObjectMapper objectMapper) {
            super(objectMapper);
        }

        @Override
        public ObjectMapper copy() {
            return new JacksonObjectMapper(this);
        }
    }

    /**
     * 将对象序列化成json字符串
     * @param object javaBean
     * @return jsonString json字符串
     */
    public static String toJsonString(Object object) {
        if (!Objects.isNull(object)) {
            try {
                return getInstance().writeValueAsString(object);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将对象序列化成 json byte 数组
     * @param object javaBean
     * @return jsonString json字符串
     */
    public static byte[] toJsonAsBytes(Object object) {
        if (!Objects.isNull(object)) {
            try {
                return getInstance().writeValueAsBytes(object);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return new byte[0];
    }

    /**
     * 将json字符串转成 JsonNode
     * @param jsonString jsonString
     * @return jsonString json字符串
     */
    public static JsonNode readTree(String jsonString) {
        if(!Strings.isNullOrEmpty(jsonString)){
            try {
                return getInstance().readTree(jsonString);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json字符串转成 JsonNode
     * @param in 输入流
     * @return json字符串
     */
    public static JsonNode readTree(InputStream in) {
        if(!Objects.isNull(in)){
            try {
                return getInstance().readTree(in);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json字符串转成 JsonNode
     * @param bytes 字符集合
     * @return jsonString json字符串
     */
    public static JsonNode readTree(byte[] bytes) {
        if(!CollectionUtils.isEmpty(Collections.singleton(bytes))){
            try {
                return getInstance().readTree(bytes);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json字符串转成 JsonNode
     * @param jsonParser JsonParser
     * @return json字符串
     */
    public static JsonNode readTree(JsonParser jsonParser) {
        if(!Objects.isNull(jsonParser)){
            try {
                return getInstance().readTree(jsonParser);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json byte 数组反序列化成对象
     * @param bytes   json bytes
     * @param valueType class
     * @param <T>       T 泛型标记
     * @return Bean
     */
    public static <T> T readValue(byte[] bytes, Class<T> valueType) {
        if(!CollectionUtils.isEmpty(Collections.singleton(bytes))){
            try {
                return getInstance().readValue(bytes, valueType);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json反序列化成对象
     * @param jsonString json字符串
     * @param valueType  class
     * @param <T>        T 泛型标记
     * @return Bean
     */
    @Nullable
    public static <T> T readValue(@Nullable String jsonString, Class<T> valueType) {
        if (!Strings.isNullOrEmpty(jsonString)) {
            try {
                return getInstance().readValue(jsonString, valueType);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json反序列化成对象
     * @param in        输入流
     * @param valueType class
     * @param <T>       T 泛型标记
     * @return Bean
     */
    public static <T> T readValue(InputStream in, Class<T> valueType) {
        if (!Objects.isNull(in)) {
            try {
                return getInstance().readValue(in, valueType);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json反序列化成对象
     * @param bytes bytes
     * @param typeReference 泛型类型
     * @param <T> T 泛型标记
     * @return Bean
     */
    public static <T> T readValue(byte[] bytes, TypeReference<T> typeReference) {
        if(!CollectionUtils.isEmpty(Collections.singleton(bytes))){
            try {
                return getInstance().readValue(bytes, typeReference);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json反序列化成对象
     * @param jsonString    json字符串
     * @param typeReference 泛型类型
     * @param <T>           T 泛型标记
     * @return Bean
     */
    public static <T> T readValue(String jsonString, TypeReference<T> typeReference) {
        if (!Strings.isNullOrEmpty(jsonString)) {
            try {
                return getInstance().readValue(jsonString, typeReference);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json反序列化成对象
     * @param in            输入流
     * @param typeReference 泛型类型
     * @param <T>           T 泛型标记
     * @return Bean
     */
    public static <T> T readValue(InputStream in, TypeReference<T> typeReference) {
        if (!Objects.isNull(in)) {
            try {
                return getInstance().readValue(in, typeReference);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json反序列化成对象
     *
     * @param bytes  bytes
     * @param javaType JavaType
     * @param <T>      T 泛型标记
     * @return Bean
     */
    public static <T> T readValue(byte[] bytes, JavaType javaType) {
        if(!CollectionUtils.isEmpty(Collections.singleton(bytes))){
            try {
                return getInstance().readValue(bytes, javaType);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json反序列化成对象
     * @param jsonString jsonString
     * @param javaType   JavaType
     * @param <T>        T 泛型标记
     * @return Bean
     */
    public static <T> T readValue(String jsonString, JavaType javaType) {
        if (!Strings.isNullOrEmpty(jsonString)) {
            try {
                return getInstance().readValue(jsonString, javaType);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将json反序列化成对象
     * @param inputStream       InputStream
     * @param javaType JavaType
     * @param <T>      T 泛型标记
     * @return Bean
     */
    public static <T> T readValue(InputStream inputStream, JavaType javaType) {
        if (!Objects.isNull(inputStream)) {
            try {
                return getInstance().readValue(inputStream, javaType);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 读取集合
     * @param bytes      bytes
     * @param elementClass elementClass
     * @param <T>          泛型
     * @return 集合
     */
    public static <T> List<T> readList(byte[] bytes, Class<T> elementClass) {
        if(!CollectionUtils.isEmpty(Collections.singleton(bytes))){
            try {
                return getInstance().readValue(bytes, getListType(elementClass));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return Collections.emptyList();
    }

    /**
     * 读取集合
     * @param inputStream      InputStream
     * @param elementClass elementClass
     * @param <T>          泛型
     * @return 集合
     */
    public static <T> List<T> readList(InputStream inputStream, Class<T> elementClass) {
        if (!Objects.isNull(inputStream)) {
            try {
                return getInstance().readValue(inputStream, getListType(elementClass));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return Collections.emptyList();
    }

    /**
     * 读取集合
     * @param jsonString      bytes
     * @param elementClass elementClass
     * @param <T>          泛型
     * @return 集合
     */
    public static <T> List<T> readList(String jsonString, Class<T> elementClass) {
        if (!Strings.isNullOrEmpty(jsonString)) {
            try {
                return getInstance().readValue(jsonString, getListType(elementClass));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return Collections.emptyList();
    }

    /**
     * 封装 map type
     * @param elementClass 集合值类型
     * @return CollectionLikeType
     */
    public static CollectionLikeType getListType(Class<?> elementClass) {
        return getInstance().getTypeFactory().constructCollectionLikeType(List.class, elementClass);
    }

    /**
     * 读取集合
     * @param content bytes
     * @return 集合
     */
    public static Map<String, Object> readMap(@Nullable byte[] content) {
        return readMap(content, Object.class);
    }

    /**
     * 读取集合
     * @param content InputStream
     * @return 集合
     */
    public static Map<String, Object> readMap(@Nullable InputStream content) {
        return readMap(content, Object.class);
    }

    /**
     * 读取集合
     * @param content bytes
     * @return 集合
     */
    public static Map<String, Object> readMap(@Nullable String content) {
        return readMap(content, Object.class);
    }

    /**
     * 读取集合
     * @param content    bytes
     * @param valueClass 值类型
     * @param <V>        泛型
     * @return 集合
     */
    public static <V> Map<String, V> readMap(@Nullable byte[] content, Class<?> valueClass) {
        return readMap(content, String.class, valueClass);
    }

    /**
     * 读取集合
     * @param content    InputStream
     * @param valueClass 值类型
     * @param <V>        泛型
     * @return 集合
     */
    public static <V> Map<String, V> readMap(@Nullable InputStream content, Class<?> valueClass) {
        return readMap(content, String.class, valueClass);
    }

    /**
     * 读取集合
     * @param content    bytes
     * @param valueClass 值类型
     * @param <V>        泛型
     * @return 集合
     */
    public static <V> Map<String, V> readMap(@Nullable String content, Class<?> valueClass) {
        return readMap(content, String.class, valueClass);
    }

    /**
     * 读取集合
     * @param bytes    bytes
     * @param keyClass   key类型
     * @param valueClass 值类型
     * @param <K>        泛型
     * @param <V>        泛型
     * @return 集合
     */
    public static <K, V> Map<K, V> readMap(@Nullable byte[] bytes, Class<?> keyClass, Class<?> valueClass) {
        if(!CollectionUtils.isEmpty(Collections.singleton(bytes))){
            try {
                return getInstance().readValue(bytes, getMapType(keyClass, valueClass));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return Collections.emptyMap();
    }

    /**
     * 读取集合
     * @param inputStream    InputStream
     * @param keyClass   key类型
     * @param valueClass 值类型
     * @param <K>        泛型
     * @param <V>        泛型
     * @return 集合
     */
    public static <K, V> Map<K, V> readMap(@Nullable InputStream inputStream, Class<?> keyClass, Class<?> valueClass) {
        if (!Objects.isNull(inputStream)) {
            try {
                return getInstance().readValue(inputStream, getMapType(keyClass, valueClass));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return Collections.emptyMap();
    }

    /**
     * 读取集合
     * @param jsonString    jsonString
     * @param keyClass   key类型
     * @param valueClass 值类型
     * @param <K>        泛型
     * @param <V>        泛型
     * @return 集合
     */
    public static <K, V> Map<K, V> readMap(@Nullable String jsonString, Class<?> keyClass, Class<?> valueClass) {
        if (!Strings.isNullOrEmpty(jsonString)) {
            try {
                return getInstance().readValue(jsonString, getMapType(keyClass, valueClass));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return Collections.emptyMap();
    }

    /**
     * 封装 map type，keyClass String
     * @param valueClass value 类型
     * @return MapType
     */
    public static MapType getMapType(Class<?> valueClass) {
        return getMapType(String.class, valueClass);
    }

    /**
     * 封装 map type
     * @param keyClass   key 类型
     * @param valueClass value 类型
     * @return MapType
     */
    public static MapType getMapType(Class<?> keyClass, Class<?> valueClass) {
        return getInstance().getTypeFactory().constructMapType(Map.class, keyClass, valueClass);
    }

    /**
     * jackson 的类型转换
     * @param fromValue   来源对象
     * @param toValueType 转换的类型
     * @param <T>         泛型标记
     * @return 转换结果
     */
    public static <T> T convertValue(Object fromValue, Class<T> toValueType) {
        return getInstance().convertValue(fromValue, toValueType);
    }

    /**
     * jackson 的类型转换
     * @param fromValue   来源对象
     * @param toValueType 转换的类型
     * @param <T>         泛型标记
     * @return 转换结果
     */
    public static <T> T convertValue(Object fromValue, JavaType toValueType) {
        return getInstance().convertValue(fromValue, toValueType);
    }

    /**
     * jackson 的类型转换
     * @param fromValue      来源对象
     * @param toValueTypeRef 泛型类型
     * @param <T>            泛型标记
     * @return 转换结果
     */
    public static <T> T convertValue(Object fromValue, TypeReference<T> toValueTypeRef) {
        return getInstance().convertValue(fromValue, toValueTypeRef);
    }

    /**
     * tree 转对象
     * @param treeNode  TreeNode
     * @param valueType valueType
     * @param <T>       泛型标记
     * @return 转换结果
     */
    public static <T> T treeToValue(TreeNode treeNode, Class<T> valueType) {
        try {
            return getInstance().treeToValue(treeNode, valueType);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 对象转 tree
     * @param fromValue fromValue
     * @param <T>       泛型标记
     * @return 转换结果
     */
    public static <T extends JsonNode> T valueToTree(Object fromValue) {
        return getInstance().valueToTree(fromValue);
    }

}
